package com.mspbots.ticketai.graderule;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.ticketai.GradeRuleInterceptorAdapter;
import com.mspbots.ticketai.model.Ticket;
import com.mspbots.ticketai.model.TicketRule;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/12/30
 * <p>
 * CUSTOM_GRADE_POINT_RULE
 * fieldName,fieldType,filterType,value,point,selected
 * datetime,String,boolean,number
 */
@Slf4j
@Service(value = "CUSTOM_GRADE_POINT_RULE")
public class CustomGradeRuleInterceptor extends GradeRuleInterceptorAdapter {

    private List<CustomParam> customParams;

    @Override
    public void prepare(TicketRule rule) {
        this.customParams = super.objectMapper.convertValue(rule.getParams(), new TypeReference<>() {
        });
    }

    @Override
    public Mono<Ticket> syncProcess(Ticket ticket) {
        List<Mono<JsonNode>> tsn = new ArrayList<>();
        customParams.stream().filter(CustomParam::isSelected).forEach(item -> tsn.add(super.scriptClient.post("execute/event/ticket",
                Map.of("id", item.getScriptId(), "payload", ticket.getExtend()), Boolean.class)
                .filter(flag -> flag)
                .map(ss -> {
                    ObjectNode jsonNodeParam = super.objectMapper.createObjectNode();
                    jsonNodeParam.put("scriptId", item.getScriptId());
                    jsonNodeParam.put("scriptName", item.getScriptName());
                    jsonNodeParam.put("point", item.getPoint());
                    return jsonNodeParam;
                })));
        return Flux.concat(tsn).collectList().map(nodes -> {
            ObjectNode extendNode = ticket.getOrderDetail() == null ? this.objectMapper.createObjectNode() : ticket.getOrderDetail().deepCopy();
            extendNode.putPOJO("custom", nodes);
            ticket.setOrderDetail(extendNode);
            ticket.setOrder(ticket.getOrder() + nodes.stream().mapToInt(node -> node.get("point").asInt()).sum());
            return ticket;
        });
    }

    @Data
    private static class CustomParam {
        private Long scriptId;
        private String scriptName;
        private Integer point;
        private boolean selected;
    }
}
